﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.IO;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Reflection;
using System.Configuration;

namespace OrganizationName.WebServices
{
    public class AssemblyServiceHandlerFactory : WebService, IHttpHandlerFactory
    {
        private static WebServiceHandlerFactory webServiceHandlerFactory = new WebServiceHandlerFactory();
        private static MethodInfo coreGetHandlerMethod = typeof(WebServiceHandlerFactory).GetMethod("CoreGetHandler", BindingFlags.Instance | BindingFlags.NonPublic);

        protected HttpRequest Request { get { return Context.Request; } }

        public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
        {
            return coreGetHandlerMethod.Invoke(webServiceHandlerFactory, new object[] { GetType(), context, context.Request, context.Response }) as IHttpHandler;
        }

        public void ReleaseHandler(IHttpHandler handler)
        {

        }
    }

    [System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.1432")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.organizationname.org/AssemblyService")]
    public class AssemblyServiceResponse
    {
        public byte[] AssemblyRawData { get; set; }
        public string ErrorMessage { get; set; }
    }

    [WebService(Namespace = "http://www.organizationname.org/AssemblyService")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class AssemblyServiceHandler : AssemblyServiceHandlerFactory
    {
        static string _AssemblyStoragePath;
        static Exception _AssemblyStoragePathReadError;

        private string GetAssemblyStoragePath()
        {
            if (string.IsNullOrEmpty(_AssemblyStoragePath) && _AssemblyStoragePathReadError == null)
            {
                lock (typeof(AssemblyServiceHandler))
                {
                    if (string.IsNullOrEmpty(_AssemblyStoragePath) && _AssemblyStoragePathReadError == null)
                    {
                        string assemblyStoragePath = null;

                        try
                        {
                            assemblyStoragePath = (string)(new System.Configuration.AppSettingsReader().GetValue("AssemblyService.AssemblyStoragePath", typeof(string)));
                        }
                        catch (Exception assemblyStoragePathReadError)
                        {
                            _AssemblyStoragePathReadError = new ConfigurationErrorsException("The AssemblyService.AssemblyStoragePath configuration setting could not be read", assemblyStoragePathReadError);
                        }

                        if (!string.IsNullOrEmpty(assemblyStoragePath))
                        {
                            try
                            {
                                assemblyStoragePath = Server.MapPath(assemblyStoragePath);
                                _AssemblyStoragePath = assemblyStoragePath;
                            }
                            catch (Exception assemblyStoragePhysicalPathTransformError)
                            {
                                _AssemblyStoragePathReadError = new ConfigurationErrorsException("The web path specified by the AssemblyService.AssemblyStoragePath configuration setting could not be mapped to a physical path", assemblyStoragePhysicalPathTransformError);
                            }

                            if (!Directory.Exists(assemblyStoragePath))
                            {
                                _AssemblyStoragePathReadError = new ConfigurationErrorsException("The directory specified by the AssemblyService.AssemblyStoragePath configuration setting not found");
                            }
                        }
                        else
                        {
                            _AssemblyStoragePathReadError = new ConfigurationErrorsException("The AssemblyService.AssemblyStoragePath configuration setting is missing, or it's value is empty");
                        }
                    }
                }
            }

            if (_AssemblyStoragePathReadError != null)
            {
                throw (_AssemblyStoragePathReadError);
            }

            return _AssemblyStoragePath;
        }

        [WebMethod]
        public AssemblyServiceResponse GetAssembly(string assemblyName)
        {
            AssemblyServiceResponse responseInstance = new AssemblyServiceResponse();
            try
            {
                AssemblyName assemblyNameInstance = new AssemblyName(assemblyName);
                string assemblyExpectedFileName = Path.Combine(GetAssemblyStoragePath(), assemblyNameInstance.Name + ".dll");
                if (File.Exists(assemblyExpectedFileName))
                {
                    responseInstance.AssemblyRawData = File.ReadAllBytes(assemblyExpectedFileName);
                }
                else
                {
                    responseInstance.ErrorMessage = "The requested assembly could not be found";
                }
            }
            catch (Exception assemblyFileLookupError)
            {
                if (assemblyFileLookupError.InnerException != null)
                {
                    responseInstance.ErrorMessage = string.Format("{0}: {1}\r\n\r\n{2}: {3}", assemblyFileLookupError.GetType().Name, assemblyFileLookupError.Message, assemblyFileLookupError.InnerException.GetType().Name, assemblyFileLookupError.InnerException.Message);
                }
                else
                {
                    responseInstance.ErrorMessage = string.Format("{0}: {1}", assemblyFileLookupError.GetType().Name, assemblyFileLookupError.Message);
                }
            }

            return responseInstance;
        }
    }
}
